#ifndef GFXMODEL_H
#define GFXMODEL_H

#include <utils/String.h>
#include <utils/Maths.h>
#include <utils/Color.h>

#include <vector>
#include <list>

struct Vertex {
	Vector    vPos;
	RGBAColor rgbaColor;
	Vector    vTexCoords;
	Vector    vNormal;
	
	Vertex() {}
	Vertex( Vector _vPos, RGBAColor _rgbaColor, Vector _vTexCoords, Vector _vNormal )
	 : vPos(_vPos), rgbaColor(_rgbaColor), vTexCoords(_vTexCoords), vNormal(_vNormal)
	 {}
};
struct Triangle {
	Vertex* pVertices[3];
	
	Triangle() { pVertices[0]=0; pVertices[1]=0; pVertices[2]=0; }
	Triangle( Vertex* pVertex1, Vertex* pVertex2, Vertex* pVertex3 )
     { pVertices[0] = pVertex1; pVertices[1] = pVertex2; pVertices[2] = pVertex3; }
};

class GfxModel
{
public:
	
	
	typedef std::list<Vertex*>             VertexArray;
	typedef std::list<Vertex*>::iterator   VertexArrayIterator;
	typedef std::list<Triangle*>           TriangleArray;
	typedef std::list<Triangle*>::iterator TriangleArrayIterator;
	
	std::list<VertexArray> m_TriStrips;
	
private:
	VertexArray    m_Vertices;
	TriangleArray  m_Triangles;
	//TODO: Consider how this might (need to) be generalised
	int            m_iTexture;
	
public:
	GfxModel() : m_iTexture(0) {}
	
	~GfxModel()
	{
		while ( m_Triangles.size() ) {
			delete m_Triangles.back();
			m_Triangles.pop_back();
		}
		while ( m_Vertices.size() ) {
			delete m_Vertices.back();
			m_Vertices.pop_back();
		}
	}
	
	GfxModel( const GfxModel& source )
	{
		VertexArray::const_iterator itVertex;
		for ( itVertex = source.m_Vertices.begin(); itVertex != source.m_Vertices.end(); ++itVertex) {
			//Create a copy of the given vertex on the heap
			Vertex* v = new Vertex( **itVertex );
			//Add a pointer to the vertex to the list
			m_Vertices.push_back( v );
		}
		
		TriangleArray::const_iterator itTriangle;
		for ( itTriangle = source.m_Triangles.begin(); itTriangle != source.m_Triangles.end(); ++itTriangle) {
			Triangle* v = new Triangle( **itTriangle );
			m_Triangles.push_back( v );
		}
		
		m_iTexture = source.m_iTexture;
	}
	
	GfxModel& operator=( const GfxModel& source )
	{
		VertexArray tmpVertices;
		VertexArray::const_iterator itVertex;
		for ( itVertex = source.m_Vertices.begin(); itVertex != source.m_Vertices.end(); ++itVertex) {
			//Create a copy of the given vertex on the heap
			Vertex* v = new Vertex( **itVertex );
			//Add a pointer to the vertex to the list
			tmpVertices.push_back( v );
		}
		
		TriangleArray tmpTriangles;
		TriangleArray::const_iterator itTriangle;
		for ( itTriangle = source.m_Triangles.begin(); itTriangle != source.m_Triangles.end(); ++itTriangle) {
			Triangle* v = new Triangle( **itTriangle );
			tmpTriangles.push_back( v );
		}
		
		while ( m_Triangles.size() ) {
			delete m_Triangles.back();
			m_Triangles.pop_back();
		}
		while ( m_Vertices.size() ) {
			delete m_Vertices.back();
			m_Vertices.pop_back();
		}
		
		m_Vertices = tmpVertices;
		m_Triangles = tmpTriangles;
		
		m_iTexture = source.m_iTexture;
	}
	
	//TODO: Implement this
	void loadFromFile( String sFilename );
	
	//void addTriangleStrip( )?
	
	Vertex* addVertex( const Vertex& vertex ) 
	{
		//Create a copy of the given vertex on the heap
		Vertex* v = new Vertex( vertex );
		//Add a pointer to the vertex to the list
		m_Vertices.push_back( v );
		//Return a pointer to the vertex
		return v;
	}
	Triangle* addTriangle( const Triangle& triangle )
	{
		if (! (triangle.pVertices[0] && triangle.pVertices[1] && triangle.pVertices[2]) )
			std::cout << "Triangle addition failed." << std::endl;
		Triangle* tri = new Triangle( triangle );
		m_Triangles.push_back( tri );
		return tri;
	}
	int&      setTexture( int iTexture )       { m_iTexture = iTexture; return m_iTexture; }
	
	const VertexArray&    getVertices() const  { return m_Vertices; }
	const TriangleArray&  getTriangles() const { return m_Triangles; }
	int                   getTexture() const   { return m_iTexture; }
	
};

#endif //GFXMODEL
